package com.zxp.mybatisplus.gen;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.IFill;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.query.DefaultQuery;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.util.*;

public class MpGen {

    /**
     * mybatis-plus代码生成器配置
     */
    // 全局策略配置提供了一些全局的设置，如作者信息、生成路径等。
    protected GlobalConfig.Builder globalConfig = new GlobalConfig.Builder();

    // 数据库表配置用于指定需要生成哪些表的代码或者排除哪些表。通过策略配置，可以灵活地控制代码生成的范围。
    protected StrategyConfig.Builder strategyConfig = new StrategyConfig.Builder();

    // 包名配置用于指定生成代码的包路径。通过配置包名，可以确保生成的代码放置在正确的目录结构中。
    protected PackageConfig.Builder packageConfig = new PackageConfig.Builder();

    protected InjectionConfig.Builder injectionConfig = new InjectionConfig.Builder().beforeOutputFile( (tableInfo, objectMap)->{
        TableInfo ti = tableInfo;
        for (TableField tf : ti.getFields()) {
            System.out.println( "propertyName:"+tf.getPropertyName() +" columnType.type:"+ tf.getColumnType().getType()  +" capitalName:"
                    + tf.getCapitalName()  +" propertyType:"+ tf.getPropertyType()  );
            Map<String, Object> customMap = tf.getCustomMap();
            customMap.put("aa","KK哈哈"); // 添加一些自定义字段数据
            tf.setCustomMap(customMap);
        }

        Map<String, Object> om = objectMap;
        Set<Map.Entry<String, Object>> entries = om.entrySet();
        for(Map.Entry<String, Object> key:entries){
            String k = key.getKey();
            Object v = key.getValue();
            System.out.println( k +":"+ v );
        }
    });

    /**
     * mysql数据源配置
     * 数据源配置用于指定需要生成代码的具体数据库。通过配置数据源，代码生成器能够连接到数据库并获取表结构信息，以便生成相应的代码。
     */
    private static DataSourceConfig DATA_SOURCE_CONFIG_MYSQL = new DataSourceConfig
            .Builder("jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useSSL=false", "root", "123456")
            .build();

    @Test
    public void genSnowyLayui(){

        //打包下载，则生成到默认目录，直接下载到项目目录则路径上加个/java
        String outputPath="d:/gen/java";
        String author="shollin"; // 作者  contextParam
        boolean enableSpringdoc = true;
        boolean enableSwagger = true; // 生成Swagger
        boolean disableOpenDir = false; //不打开目录
        boolean disableServiceInterface = true; //不生成service接口
        String[] removeTablePrefix = new String[]{"t_"}; // 移除表前缀
        String[] includeTables = new String[]{"t_simple"}; // 要生成哪个表, 为空则生成所有表
        String parentPackage="com.zxp.snowy"; // 父包名
        String moduleName= "test"; // 模块名

        String tplPath="templates"; // 模板路径  snowyTpl
        String mapperXmlTemplate=tplPath+"/mapper.xml.vm";
        String mapperTemplate=tplPath+"/mapper.java.vm";
        String controllerTemplate=tplPath+"/controller.java.vm";
        String serviceTemplate=tplPath+"/service.java.vm";
        String serviceImplTemplate=tplPath+"/serviceImpl.java.vm";
        String entityTemplate=tplPath+"/entity.java.vm";
        String indexHtmlTemplate=tplPath+"/index.html.vm";
        String formHtmlTemplate=tplPath+"/form.html.vm";
        String jsTemplate=tplPath+"/js.js.vm";
        String sqlTemplate=tplPath+"/XnMysql.sql.vm";
        String exceptionEnumTemplate = tplPath+"/ExceptionEnum.java.vm";

        String specParamsTemplatePath = tplPath+"/Param.java.vm";
        String dtoTemplate=tplPath+"/dto.java.vm";

        // 公共字段填充
        ArrayList<IFill> tableFills = new ArrayList<>();
        tableFills.add(new Column("CREATE_TIME", FieldFill.INSERT)); // Column为基于数据库字段填充 Property为基于模型属性填充
        tableFills.add(new Column("UPDATE_TIME", FieldFill.UPDATE));
        tableFills.add(new Column("CREATE_USER", FieldFill.INSERT));
        tableFills.add(new Column("UPDATE_USER", FieldFill.UPDATE));

        List<CustomFile> customFiles = new ArrayList<>();
        customFiles.add(new CustomFile.Builder().fileName("Param.java").templatePath(specParamsTemplatePath).packageName("param").enableFileOverride().build());
        customFiles.add(new CustomFile.Builder().fileName("DTO.java").templatePath(dtoTemplate).packageName("dto").enableFileOverride().build());
        customFiles.add(new CustomFile.Builder().fileName("ExceptionEnum.java").templatePath(exceptionEnumTemplate).packageName("enums").enableFileOverride().build());
        customFiles.add(new CustomFile.Builder().fileName("Menu.sql").templatePath(formHtmlTemplate)
                .filePath(outputPath + "/_sql").enableFileOverride().build()); // 增加、编辑的表单
        customFiles.add(new CustomFile.Builder().fileName("Form.html").templatePath(formHtmlTemplate)
                .filePath(outputPath + "/html").enableFileOverride().build()); // 增加、编辑的表单
        customFiles.add(new CustomFile.Builder().fileName("Index.html").templatePath(indexHtmlTemplate)
                .filePath(outputPath + "/html").enableFileOverride().build()); // html页面，分页列表

        HashMap<String, Object> paramsMap = Maps.newHashMap(); // 放自定义的数据
        List<Long> sqlMenuId = Lists.newArrayList(6L);
        String menuPids = "[0],[1264622039642255341]"; // 将1264622039642255341 替换即可
        for (int i = 0; i < 7; i++) {
            sqlMenuId.add(IdUtil.getSnowflakeNextId());
        }
        paramsMap.put("sqlMenuId", sqlMenuId);  // 生个七个菜单、权限的主键id
        paramsMap.put("EntitySpecResult",parentPackage + "." + StrUtil.blankToDefault(moduleName,"") + ".dto"); // 放自定义的数据 param的路径
        paramsMap.put("EntitySpecParams",parentPackage + "." + StrUtil.blankToDefault(moduleName,"") + ".param"); // 放自定义的数据 param的路径

        //第一步：数据源配置 父类实现
        // 第二步：全局配置
        globalConfig
                .dateType(DateType.ONLY_DATE)
                .author(author) // 作者
                .outputDir(outputPath); // 输出路径
        if (disableServiceInterface) { // 不生成service接口
            globalConfig.disableServiceInterface();
        }
        if (disableOpenDir) { // 不打开目录
            globalConfig.disableOpenDir();
        }
        if (enableSpringdoc) { //Springdoc
            globalConfig.enableSpringdoc();
        }
        if (enableSwagger) { //Swagger
            globalConfig.enableSwagger();
        }

        // 第三步：包配置
        packageConfig.parent(parentPackage);
        if (ObjectUtil.isNotEmpty(moduleName)) {
            moduleName = StrUtil.removeAll(moduleName,'/','\\');
        }
        packageConfig.moduleName( moduleName );
        packageConfig.xml("mapper.mapping");
        packageConfig.service("service");
        packageConfig.serviceImpl("service.impl");


        // 第四步：策略配置 重要
        // 大写命名 setCapitalMode(false)
        //strategyConfig.enableCapitalMode();

        // 此处可以移除表前缀表前缀
        strategyConfig.addTablePrefix(removeTablePrefix);

        // 需要生成的表
        strategyConfig.addInclude(includeTables);

        // 生成实体类的配置
        strategyConfig.entityBuilder()
            .idType(IdType.ASSIGN_ID) // 主键生成策略
            .addTableFills(tableFills) // 公共字段填充
            .naming(NamingStrategy.underline_to_camel) // 表名生成策略
            .columnNaming(NamingStrategy.underline_to_camel) // 列名生成策略
            //.enableChainModel()  //开启链式模式
            .addIgnoreColumns() // 忽略的字段
            .enableLombok()
            .enableTableFieldAnnotation() // 开启字段注解
            //.enableColumnConstant() // 是否需要列常量，会在下面加上常量
            //.enableActiveRecord() // 开启AR模式
            .enableFileOverride(); // 覆盖已生成的文件

        strategyConfig.mapperBuilder()
                .enableBaseColumnList() // 通用查询结果列
                .enableBaseResultMap()//  通用查询映射结果
                .mapperXmlTemplate(mapperXmlTemplate) // mapper xml模板
                .mapperTemplate(mapperTemplate) // mapper模板
                .enableFileOverride(); // 覆盖已生成的文件

        // 生成controller的配置
        strategyConfig.controllerBuilder()
                .template(controllerTemplate)
                .enableFileOverride(); // 覆盖已生成的文件

        // 生成service serviceImpl的配置
        //如果不生成接口，就走不生成接口的模板
        strategyConfig.serviceBuilder()
                .formatServiceFileName("%sService") // 默认会生成这样的： IUserService
                .serviceTemplate(serviceTemplate)
                .serviceImplTemplate(serviceImplTemplate)
                .enableFileOverride(); // 覆盖已生成的文件


        // 设置自定义输出文件
        AutoGenerator generator = new AutoGenerator(DATA_SOURCE_CONFIG_MYSQL);
        generator.global(globalConfig.build())
                .packageInfo(packageConfig.build())
                .strategy(strategyConfig.build())
                .injection(injectionConfig.customFile(customFiles).customMap(paramsMap).build());// 自定义,重要
        generator.execute();

    }



}
